package com.sicpa.common.ftp;

import com.sicpa.common.config.FtpConfig;
import com.sicpa.common.utils.spring.SpringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.UnknownHostException;

/**
 * FtpConnection
 *
 * @author lwf
 */
public class FtpConnection {

    private static Logger log = LoggerFactory.getLogger(FtpConnection.class);

    private FTPClient ftp = new FTPClient();

    private boolean isConnected = false;

    private static final String ANONYMOUS_LOGIN = "anonymous";

    private FtpConfig ftpConfig = SpringUtils.getBean(FtpConfig.class);

    /**
     * 构造函数
     */
    public FtpConnection() {
        isConnected = false;
        ftp.setDefaultTimeout(ftpConfig.getDefaultTimeoutSecond() * 1000);
        ftp.setConnectTimeout(ftpConfig.getConnectTimeoutSecond() * 1000);
        ftp.setDataTimeout(ftpConfig.getDataTimeoutSecond() * 1000);
        try {
            initConnect(ftpConfig.getHostname(), ftpConfig.getPort(), ftpConfig.getUsername(), ftpConfig.getPwd());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 判断链接是否存续
     *
     * @return
     */
    public boolean isConnnect() {
        return ftp.isConnected();
    }

    /**
     * 重新初始化链接
     *
     * @throws IOException
     */
    public void intiConnect() throws IOException {
        ftp.setDefaultTimeout(ftpConfig.getDefaultTimeoutSecond() * 1000);
        ftp.setConnectTimeout(ftpConfig.getConnectTimeoutSecond() * 1000);
        ftp.setDataTimeout(ftpConfig.getDataTimeoutSecond() * 1000);
        initConnect(ftpConfig.getHostname(), ftpConfig.getPort(), ftpConfig.getUsername(), ftpConfig.getPwd());
    }

    /**
     * 初始化连接
     *
     * @param host
     * @param port
     * @param user
     * @param password
     * @throws IOException
     */
    private void initConnect(String host, int port, String user, String password) throws IOException {
        try {
            ftp.connect(host, port);
        } catch (UnknownHostException ex) {
            throw new IOException("Can't find FTP server '" + host + "'");
        }
        int reply = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            disconnect();
            throw new IOException("Can't connect to server '" + host + "'");
        }
        if (ftpConfig.getEnableAnonymous()) {
            user = ANONYMOUS_LOGIN;
        }
        if (!ftp.login(user, password)) {
            isConnected = false;
            disconnect();
            throw new IOException("Can't login to server '" + host + "'");
        } else {
            isConnected = true;
        }
    }

    /**
     * 上传文件
     *
     * @param path
     * @param ftpFileName
     * @param localFile
     * @throws IOException
     */
    public void upload(String path, String ftpFileName, MultipartFile localFile) throws IOException {
        //检查本地文件是否存在
        if (localFile.isEmpty()) {
            throw new IOException("This file doesn't exist.");
        }
        //设置工作路径
        setWorkingDirectory(path);
        //上传
        InputStream in = null;
        try {
            //被动模式
            ftp.enterLocalPassiveMode();
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            in = new BufferedInputStream(localFile.getInputStream());
            //保存文件
            if (!ftp.storeFile(ftpFileName, in)) {
                throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");
            }
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    }

    /**
     * 下载文件 *
     *
     * @param pathname FTP服务器文件目录 *
     * @param filename 文件名称 *
     * @return
     */
    public void downloadFile(String pathname, String filename, OutputStream os) {
        try {
            // 如果远程目录不存在，则递归创建远程服务器目录
            if (!pathname.equalsIgnoreCase("/") && !ftp.changeWorkingDirectory(new String(pathname))) {
                int start = 0;
                int end = 0;
                if (pathname.startsWith("/")) {
                    start = 1;
                } else {
                    start = 0;
                }
                end = pathname.lastIndexOf("/");
                String subDirectory = new String(pathname.substring(start, end));

                boolean dir = ftp.changeWorkingDirectory(subDirectory);
                if (dir) {
                    FTPFile[] ftpFiles = ftp.listFiles();
                    for (FTPFile file : ftpFiles) {
                        if (filename.equalsIgnoreCase(file.getName())) {
                            ftp.retrieveFile(file.getName(), os);
                        }
                    }
                } else {
                    log.debug("服务器编码方式可能有问题，请检查！");
                    return;
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 关闭连接
     *
     * @throws IOException
     */
    public void disconnect() throws IOException {
        if (ftp.isConnected()) {
            try {
                ftp.logout();
                ftp.disconnect();
                isConnected = false;
            } catch (IOException ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    }

    /**
     * 设置工作路径
     *
     * @param dir
     * @return
     */
    private boolean setWorkingDirectory(String dir) {
        if (!isConnected) {
            return false;
        }
        //如果目录不存在创建目录
        try {
            if (createDirecroty(dir)) {
                return ftp.changeWorkingDirectory(dir);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 是否连接
     *
     * @return
     */
    public boolean isConnected() {
        return isConnected;
    }

    /**
     * 创建目录
     *
     * @param remote
     * @return
     * @throws IOException
     */
    private boolean createDirecroty(String remote) throws IOException {
        boolean success = true;
        // 如果远程目录不存在，则递归创建远程服务器目录
        if (!remote.equalsIgnoreCase("/") && !ftp.changeWorkingDirectory(new String(remote))) {
            int start = 0;
            int end = 0;
            if (remote.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = remote.indexOf("/", start);
            while (true) {
                String subDirectory = new String(remote.substring(start, end));
                if (!ftp.changeWorkingDirectory(subDirectory)) {
                    if (ftp.makeDirectory(subDirectory)) {
                        ftp.changeWorkingDirectory(subDirectory);
                    } else {
                        return false;
                    }
                }
                start = end + 1;
                end = remote.indexOf("/", start);
                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break;
                }
            }
        }
        return success;
    }

}
